import { useState } from "react";
import { computed } from "nanostores";
import { useStore } from "@nanostores/react";
import {
  CommandGroup,
  CommandGroupHeading,
  CommandItem,
  Text,
  toast,
  useSelectedAction,
  useResetActionIndex,
} from "@webstudio-is/design-system";
import type { Instance, StyleSource } from "@webstudio-is/sdk";
import { $selectedStyleSources, $styleSources } from "~/shared/nano-states";
import {
  deleteStyleSource,
  DeleteStyleSourceDialog,
  RenameStyleSourceDialog,
  $styleSourceUsages,
} from "~/builder/shared/style-source-utils";
import { InstanceList, showInstance } from "../shared/instance-list";
import {
  $commandContent,
  closeCommandPanel,
  focusCommandPanel,
} from "../command-state";
import type { BaseOption } from "../shared/types";

export type TokenOption = BaseOption & {
  type: "token";
  token: Extract<StyleSource, { type: "token" }>;
  usages: number;
};

export const $tokenOptions = computed(
  [$styleSources, $styleSourceUsages],
  (styleSources, styleSourceUsages) => {
    const tokenOptions: TokenOption[] = [];
    for (const styleSource of styleSources.values()) {
      if (styleSource.type !== "token") {
        continue;
      }
      tokenOptions.push({
        terms: ["tokens", styleSource.name],
        type: "token",
        token: styleSource,
        usages: styleSourceUsages.get(styleSource.id)?.size ?? 0,
      });
    }
    return tokenOptions;
  }
);

const selectToken = (
  instanceId: Instance["id"],
  tokenId: StyleSource["id"]
) => {
  showInstance(instanceId, "style");
  const selectedStyleSources = new Map($selectedStyleSources.get());
  selectedStyleSources.set(instanceId, tokenId);
  $selectedStyleSources.set(selectedStyleSources);
};

const TokenInstances = ({ tokenId }: { tokenId: StyleSource["id"] }) => {
  const usages = useStore($styleSourceUsages);
  const usedInInstanceIds = usages.get(tokenId) ?? new Set();

  return (
    <InstanceList
      instanceIds={usedInInstanceIds}
      onSelect={(instanceId) => {
        selectToken(instanceId, tokenId);
        closeCommandPanel();
      }}
    />
  );
};

export const TokensGroup = ({ options }: { options: TokenOption[] }) => {
  const action = useSelectedAction();
  const resetActionIndex = useResetActionIndex();
  const [tokenDialog, setTokenDialog] = useState<
    | (Extract<StyleSource, { type: "token" }> & {
        action: "rename" | "delete";
      })
    | undefined
  >();

  return (
    <>
      <CommandGroup
        name="token"
        heading={<CommandGroupHeading>Tokens</CommandGroupHeading>}
        actions={["find", "rename", "delete"]}
      >
        {options.map(({ token, usages }) => (
          <CommandItem
            key={token.id}
            // preserve selected state when rerender
            value={token.id}
            onSelect={() => {
              if (action === "find") {
                $commandContent.set(<TokenInstances tokenId={token.id} />);
              }
              if (action === "rename") {
                setTokenDialog({ ...token, action: "rename" });
              }
              if (action === "delete") {
                setTokenDialog({ ...token, action: "delete" });
              }
            }}
          >
            <Text variant="labelsTitleCase">
              {token.name}{" "}
              <Text as="span" color="moreSubtle">
                {usages === 0
                  ? "unused"
                  : `${usages} ${usages === 1 ? "usage" : "usages"}`}
              </Text>
            </Text>
          </CommandItem>
        ))}
      </CommandGroup>
      <RenameStyleSourceDialog
        styleSource={tokenDialog?.action === "rename" ? tokenDialog : undefined}
        onClose={() => {
          setTokenDialog(undefined);
          resetActionIndex();
          focusCommandPanel();
        }}
        onConfirm={(_styleSourceId, newName) => {
          toast.success(
            `Token renamed from "${tokenDialog?.name}" to "${newName}"`
          );
          setTokenDialog(undefined);
        }}
      />
      <DeleteStyleSourceDialog
        styleSource={tokenDialog?.action === "delete" ? tokenDialog : undefined}
        onClose={() => {
          setTokenDialog(undefined);
          resetActionIndex();
          focusCommandPanel();
        }}
        onConfirm={(styleSourceId) => {
          deleteStyleSource(styleSourceId);
          toast.success(`Token "${tokenDialog?.name}" deleted`);
          setTokenDialog(undefined);
        }}
      />
    </>
  );
};
